package it.crudity.web.json;

import java.io.IOException;
import java.lang.reflect.Method;

import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;

public class FilteredMappingJacksonHttpMessageConverter extends MappingJacksonHttpMessageConverter {

	/***
	 * It's private in the super class :(
	 */
	private boolean prefixJson;

	@Override
	public void setPrefixJson(boolean prefixJson) {
		this.prefixJson = prefixJson;
		super.setPrefixJson(prefixJson);
	}

	@Override
	protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException,
			HttpMessageNotWritableException {

		if (o instanceof JsonFilteredBean) {
			JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType());
			ObjectMapper objectMapper = new ObjectMapper();
			Class<?> mixin = ((JsonFilteredBean) o).mixin();
			objectMapper.getSerializationConfig().addMixInAnnotations(Object.class, mixin);
			JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(),
					encoding);

			if (prefixJson)
				jsonGenerator.writeRaw("{} && ");

			objectMapper.writeValue(jsonGenerator, o);
		} else
			super.writeInternal(o, outputMessage);
	}

	
	/***
	 * It's private in the super class :(
	 */
	protected JsonEncoding getEncoding(MediaType type) {
		JsonEncoding encoding = null;
		try {
			Method m = MappingJacksonHttpMessageConverter.class.getDeclaredMethod("getEncoding", MediaType.class);
			m.setAccessible(true);
			encoding = (JsonEncoding) m.invoke(this, type);
			return encoding;
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			// Impossible unless we change
			// MappingJacksonHttpMessageConverter class version
			throw new RuntimeException(e);
		}
	}
}
